package com {
	import com.adobe.serialization.json.JSON;
	import com.utils.Helper;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;

	/**
	 * 数据层基类
	 * @author Liseen
	 */
	public class DataBase extends SuperBase {
		protected var _onConnect:Function;
		protected var _onClose:Function;
		protected var _ctrl:Controller;
		protected var _view:View;
		protected var _sock:Socket;
		protected var _notAllowList:Object;
		private var _host:String;
		private var _port:int;
		private var _useProxy:Boolean;
		private var _connectSucceed:Boolean;
		private var pack_len:int = -1;
		private var buffer:ByteArray;
		private var _eventList:Object;
		private var _event:EventDispatcher;

		public function DataBase() {
			this._notAllowList = {};
			this._sock = new Socket();
			_eventList = {};
			_event = new EventDispatcher();
		}

		/**
		 * 链接回调
		 */
		public function set onConnect(value:Function):void {
			this._onConnect = value;
		}

		/**
		 * 关闭链接回调
		 */
		public function set onClose(value:Function):void {
			_onClose = value;
		}

		/**
		 * 初始化数据层
		 * @param	view	视图层
		 * @param	ctrol	控制层
		 */
		public function init(view:View, ctrol:Controller):void {
			this._view = view;
			this._ctrl = ctrol;
		}

		/**
		 * 链接服务器
		 * @param	host
		 * @param	port
		 */
		public function connect(host:String, port:int):void {
			this._host = host;
			this._port = port;
			this.addListener();
			if (this._sock.connected) {
				this._sock.close();
			}
			this._sock.connect(this._host, this._port);
		}

		/**
		 * 关闭服务器链接
		 */
		public function close():void {
			if (this._sock && this._sock.connected) {
				this._sock.close();
			}
		}

		/**
		 * 客户端往服务器发送数据
		 * @param	protocalObj		协议对象
		 * @param	callBack		回调
		 * @param	parameterList	参数列表
		 * @param	_arg4
		 */
		public function call(protocalObj:Object, callBack:Function, parameterList:Array, _notAllow:Boolean = true):void {
			if (this._sock.connected == false) {
//				_view.alert.socketClosed("服务器链接失败");
				return;
			}

			var moduleID:int = protocalObj["module"];
			var actionID:int = protocalObj["action"];

			if (this.hasNotAllow(moduleID, actionID)) {
				return;
			}

			if (false == _notAllow) {
				this.addNotAllow(moduleID, actionID);
			}

			if (callBack is Function) {
				this.patchBase(moduleID, actionID, this.patchHandler(moduleID, actionID, callBack));
			}
			this.netCall(moduleID, actionID, protocalObj["request"], parameterList);
		}

		protected function hasNotAllow(_module:int, _act:int):Boolean {
			var _actObj:Object;
			var _exsitNotAllow:Number = this._notAllowList[Protocol.concat(_module, _act)] || 0;
			if (_exsitNotAllow == 0 || (new Date()).time - _exsitNotAllow > 900) {
				return (false);
			}
			_actObj = Protocol.lookupProtocol(_module, _act);
			Helper.alert(Protocol.getProtocolDescription(_actObj["request"]) + " 请求间隔太短(900ms)。");
			return true;
		}

		protected function addNotAllow(_module:int, _act:int):void {
			this._notAllowList[Protocol.concat(_module, _act)] = new Date().time;
		}


		/**
		 * 补丁处理
		 * @param	protocalObj		协议对象
		 * @param	callBack		回调方法
		 */
		public function patch(protocalObj:Object, callBack:Function):void {
			var moduleID:int = protocalObj["module"];
			var actionID:int = protocalObj["action"];
			this.patchBase(moduleID, actionID, this.patchHandler(moduleID, actionID, callBack));
			Protocol.addWired(protocalObj);
		}

		/**
		 * 删除补丁处理
		 * @param	protocalObj	协议对象
		 */
		public function cancelPatch(protocalObj:Object):void {
			var moduleID:int = protocalObj["module"];
			var actionID:int = protocalObj["action"];
			Protocol.removeWired(moduleID, actionID);
			this.cancelPatchBase(moduleID, actionID);
		}

		private function patchHandler(_arg1:uint, _arg2:uint, _arg3:Function):Function {
			var modId:uint = _arg1;
			var funId:uint = _arg2;
			var callback:Function = _arg3;
			return (function(_arg1:Event):void {
				if (!Protocol.keepAlive(modId, funId)) {
					cancelPatchBase(modId, funId);
				}
				callback();
			})
		}

		private function netCall(_arg1:uint, _arg2:uint, _arg3:Array, _arg4:Array):void {
			var _local5:ByteArray = new ByteArray();
			_local5.writeByte(_arg1);
			_local5.writeByte(_arg2);
			var _local6:ByteArray = Protocol.synthesize(_arg4, _arg3);
			this._sock.writeInt((_local5.length + _local6.length));
			this._sock.writeBytes(_local5, 0, _local5.length);
			this._sock.writeBytes(_local6, 0, _local6.length);
			this._sock.flush();
			trace("[Send](M:" + _arg1 + " F:" + _arg2 + ") Data:" + JSON.encode(_arg4));
		}


		protected function createObject(_arg1:Class, _arg2:String = ""):Object {
			_arg2 = (_arg1 + "");
			_arg2 = _arg2.replace(/Data\]$/, "");
			return (createObjectBase(_arg1, _arg2, this._view, this._ctrl, (this as Data)));
		}

		private function addListener():void {
			this._sock.addEventListener(Event.CONNECT, this.onConnectHandler);
			this._sock.addEventListener(IOErrorEvent.IO_ERROR, this.onIoErrorHandler);
			this._sock.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onSecurityErrorHandler);
			this._sock.addEventListener(ProgressEvent.SOCKET_DATA, this.onSocketDataHandler);
			this._sock.addEventListener(Event.CLOSE, this.onCloseHandler);
		}

		private function removeListener():void {
			this._sock.removeEventListener(Event.CONNECT, this.onConnectHandler);
			this._sock.removeEventListener(IOErrorEvent.IO_ERROR, this.onIoErrorHandler);
			this._sock.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onSecurityErrorHandler);
			this._sock.removeEventListener(ProgressEvent.SOCKET_DATA, this.onSocketDataHandler);
			this._sock.removeEventListener(Event.CLOSE, this.onCloseHandler);
		}

		private function onConnectHandler(event:Event):void {
			var byteArray:ByteArray;
			if (this._useProxy) {
				trace("使用代理链接");
				byteArray = new ByteArray();
				byteArray.writeInt(6);
				byteArray.writeByte(100);
				byteArray.writeByte(0);
				byteArray.writeInt(this._port);
				this._sock.writeBytes(byteArray, 0, byteArray.length);
				this.onConnectHandlerReal();
			} else {
				this.onConnectHandlerReal();
			}
		}

		private function onConnectHandlerReal():void {
			this._connectSucceed = true;
			if (this._onConnect is Function) {
				this._onConnect();
				this._onConnect = null;
			}
		}

		private function onIoErrorHandler(event:IOErrorEvent):void {
			if (this._useProxy == false) {
				this.connectProxy();
			} else {
//				this._view.alert.socketClosed("连接不到服务器！", (((("Socket 错误。 URL: " + this._host) + ":") + this._port) + "，该地址没有提供Socket服务。"));
					//this._view.resetHost();
			}
		}

		private function onSecurityErrorHandler(event:SecurityErrorEvent):void {
			if (this._useProxy == false) {
				this.connectProxy();
			} else {
//				this._view.alert.socketClosed("安全沙箱冲突！", (((("安全沙箱冲突: 不能从" + this._host) + ":") + this._port) + "加载数据。"));
					//this._view.resetHost();
			}
		}

		private var byteBuffer:ByteArray = new ByteArray();

		private function onSocketDataHandler(event:ProgressEvent):void {
			while (this._sock.bytesAvailable >= this.pack_len) {
				if ((this.pack_len == -1) && (this._sock.bytesAvailable >= 4)) {
					this.pack_len = this._sock.readUnsignedInt();
				}
				if (this.pack_len == -1) {
					return;
				}
				if (this._sock.bytesAvailable < this.pack_len) {
					return;
				}
				this.buffer = new ByteArray();
				this._sock.readBytes(this.buffer, 0, this.pack_len);
				this.parseSocketData(this.buffer);
				this.pack_len = -1;
			}
		}

		protected function parseSocketData(byteArray:ByteArray):void {

		}

		protected function removeNotAllow(_arg1:int, _arg2:int):void {

		}

		private function connectProxy():void {
			if (true == this._connectSucceed) {
				//this._view.tip2.showAlert(DataBaseLang.);
				return;
			}
			this._sock.close();
			this.removeListener();
			this._useProxy = true;
			this._sock = new Socket();
			this.addListener();
			this._sock.connect(this._host, 443);
		}

		private function onCloseHandler(_arg1:Event):void {
			//this._view.tip2.showAlert(DataBaseLang.);
			//this._view.resetHost();
			if (this._onClose is Function) {
				this._onClose();
			}
		}

		private function patchBase(mod:uint, fun:uint, _arg3:Function):void {
			var evtKey:String = Protocol.concat(mod, fun);
			if (this._eventList[evtKey] is Function) {
				this.cancelPatchBase(mod, fun);
			}
			this._eventList[evtKey] = _arg3;
			this._event.addEventListener(evtKey, _arg3);
		}

		private function cancelPatchBase(mod:uint, fun:uint):void {
			var evtKey:String = Protocol.concat(mod, fun);
			var entListener:Function = this._eventList[evtKey];
			if (entListener is Function) {
				this._event.removeEventListener(evtKey, entListener);
			}
		}

		protected function dispatch(_arg1:uint, _arg2:uint):void {
			var _local4:Object;
			var _local3:String = Protocol.concat(_arg1, _arg2);
			if (this._eventList[_local3] is Function) {
				this._event.dispatchEvent(new Event(_local3));
			} else {
				_local4 = Protocol.lookupProtocol(_arg1, _arg2);
				trace("[response]接口没有注册UI回调方法：", Protocol.getProtocolDescription(_local4["request"]));
			}
		}
	}

}
